package chapter2.src.com.kkb.array;

/**
 * @author : wushikai
 * <p>
 * date : 2021-03-09
 * 看HashMap 的源码之前, 这个一定得搞懂;
 * 这个类展示 二进制数 运算符 操作;
 *  0 是我妈 1 是我爸;
 *  左手右手一个慢动作
 *  jdk的作者已经把位运算的运用做到出神入化的境界了;
 *
 */
public class OffsetDemo {


    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 将整型数字转换为二进制字符串，一共32位，不舍弃前面的0
     * @param number 整型数字
     * @return 二进制字符串
     */
    private static   String get32BitBinString(int number) {
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < 32; i++){

            sBuilder.append(number & 1);
            number = number >>> 1;
        }
        return sBuilder.reverse().toString();
    }


    /**
     * 将整型数字转换为二进制字符串，舍弃前面的0
     * @param number 整型数字
     * @return 二进制字符串
     */
    private  String getSimpleBinString(int number) {
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < 32; i++){
            sBuilder.append(number & 1);
            number = number >>> 1;
        }
        int index = sBuilder.reverse().indexOf("1");
        return sBuilder.substring(index);
    }


    public static void testRightShift() {

        int i = 16;
        System.out.println(i >> 1); // 8
        System.out.println(i >> 2); // 4
        System.out.println(i >> 3); // 2
        System.out.println(i >> 4); //16 / 2的4次方 1
        System.out.println(i >> 5); //00000001 --> 00000000
        System.out.println(i >> 6); // 0000000 --> 00000000
        System.out.println(i);

        System.out.println("--------------------------------");

        i = 15;
        System.out.println(i >> 1); // 00001111 --> 00000111  7
        System.out.println(i >> 2);  //00000111  --> 00000011  3
        System.out.println(i >> 3);  // 00000011 --> 00000001  1
        System.out.println(i >> 4); //00000001 --> 00000000    0
        System.out.println(i >> 5); //00000000 --> 00000000    0


    }


    public static void testLeftShift() {

        int i = 1;
        System.out.println(i << 1);  // * 2
        System.out.println(i << 2);  // * 4
        System.out.println(i << 3);
        System.out.println(i << 15); // * 2 的15 次方
        System.out.println(i << 31); // 最小负数
        System.out.println(i << 32);  // 1  这种计算机底层的没有办法给你看源码


    }

    /**
     * 在计算机系统中，数值一律用补码来表示。
     * 负数的补码：是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1
     * [-1] = [10000001]原 = [11111110]反 = [11111111]补
     * <p>
     * 移位运算符 : Shift Operators,Shifting operations,Bitwise Shift,
     * 位移运算符 : Shift operator,Shift Bitwise Operators,
     */
    public static void testShift() {
        int i = 16;
        System.out.println(i << 32);
        System.out.println(i >>> 32); //???????
        //对于正数而言，>>和>>>没区别。
        System.out.println(Integer.toBinaryString(-2)); // 10000000 00000000 00000000 00000010   取反加1 --> 补码  11111111 11111111 11111111 11111110
        System.out.println(-2 >>> 1);  //11111111 11111111 11111111 11111110  --> 01111111 111111111 11111111 11111111
        System.out.println(Integer.toBinaryString(-2 >>> 1)); //-> 01111111111111111111111111111111 <-
        System.out.println(-2 >> 1);
        System.out.println(Integer.toBinaryString(-2 >> 1));  //-> 11111111111111111111111111111111 <-

        System.out.println(-1 >>> 1);  //11111111111111111111111111111111  --> 01111111 111111111 11111111 11111111
        //对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常需要转换成原码在计算其数值.
        System.out.println(Integer.toBinaryString(-1)); //11111111111111111111111111111111
        System.out.println(Integer.toBinaryString(1)); //1
        System.out.println(Integer.toBinaryString(2)); //10
        System.out.println(Float.floatToIntBits(-1));
    }


    /**
     * 非运算符 运算规则：如果位为0，结果是1，如果位为1，结果是0.
     * <p>
     * 比如：~37
     * <p>
     * 在Java中，所有数据的表示方法都是以补码的形式表示，如果没有特殊说明，Java中的数据类型默认是int,int数据类型的长度是8位，一位是四个字节，就是32字节，32bit.
     * <p>
     * 8转为二进制是100101.
     * <p>
     * 补码后为： 00000000 00000000 00000000 00100101
     * <p>
     * 取反为：    11111111 11111111 11111111 11011010
     * <p>
     * 因为高位是1，所以原码为负数，负数的补码是其绝对值的原码取反，末尾再加1。
     * <p>
     * 因此，我们可将这个二进制数的补码进行还原： 首先，末尾减1得反码：11111111 11111111 11111111 11011001 其次，将各位取反得原码：
     * <p>
     * 00000000 00000000 00000000 00100110，此时二进制转原码为38
     * <p>
     * 所以~37 = -38.
     */
    public static void testInverter() {


        System.out.println(1 & 2);  //0
        System.out.println(1 | 2);  //3
        System.out.println(1 ^ 2);  //3
        System.out.println(~1);     //-2
        System.out.println(~2);     //-3
        System.out.println(~37);    //-38
        System.out.println(~0);     //-1
        System.out.println(~-1);    //0


    }

    private final static char[] digits = {'0', '1'};

    /**
     * 将int型整数转成32位的2进制形式
     *
     * @param num
     * @return String
     */
    public static String toFullBinaryString(int num) {
        char[] buf = new char[32];
        int pos = 32;
        int mask = 1;
        do {
            buf[--pos] = digits[num & mask];
            // if (pos %8 ==0){}
            num >>>= 1;
        }
        while (pos > 0);

        return new String(buf, pos, 32);
    }


    /**
     * 返回比他大或者等于他的2 的次幂; 例如 7 返回8  8 返回8 9返回16
     * 根据位运算 不需要判断;
     * 位运算这招 谁能比我骚
     */
    static final int tableSizeFor(int cap) {
        System.out.println("-----------------------------------------");
        int n = cap - 1;
        n |= n >>> 1;
        System.out.println(toFullBinaryString(n));
        n |= n >>> 2;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 4;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 8;
        System.out.println(Integer.toBinaryString(n));
        n |= n >>> 16;
        System.out.println(Integer.toBinaryString(n));
        int i = (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        System.out.println(i);
        return i;
    }


    /**
     * &= 按位与赋值
     * <p>
     * |= 按位或赋值
     * <p>
     * ^= 按 位异或赋值
     * <p>
     * >>= 右移赋值
     * <p>
     * >>>= 右移赋值，左边空出的位以0填充
     * <p>
     * <<= 左 移赋值
     */
    public static void test5() {
        int i = 1;
        System.out.println(i &= 2);
        i = 1;
        System.out.println(i >>= 1);


    }

    /**
     * 这个公式没法证明, 但是 可以预感它成立 ;
     * i = 15
     * i % 32 = 15
     * i & (32 - 1) = 15
     * 00000000000000000000000000001111  15
     * 00000000000000000000000000011111  31
     *
     * i =33
     * i % 32 = 1
     * i & (32 - 1) = 1
     * 00000000000000000000000000100001   33
     * 00000000000000000000000000011111   31
     */
    public static void testHash() {


        for (int i = 0; i < Integer.MAX_VALUE; i++) {

            if (i == 15 || i == 33){

                System.out.println(  get32BitBinString (i));
                System.out.println(  get32BitBinString((32 - 1)) );
                System.out.println("i % 32 = " + i % 32);
                System.out.println("i & (32 - 1) = " + ( i & (32 - 1))  );

            }

            if ((i % 32) != (i & (32 - 1))) {
                System.out.println(i);
                System.out.println("公式不成立");
                break;
            }
        }


    }



    public  static void testHighDigitOp( ){

        Integer key = 65538;
        int h = key.hashCode();  //Integer 的 hashcode 就是它的值本身
        System.out.println(toFullBinaryString(h));
        System.out.println(toFullBinaryString( h >>> 16 )   +  " =     h >>> 16  ");
        int  i =  (h) ^ (h >>> 16);

        System.out.println(i);



    }



    public static void main(String[] args) {


        testHighDigitOp();
    }


}
